package com.remoter.basic.context.support;

import java.io.IOException;
import java.net.InetSocketAddress;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.remoter.basic.bean.support.ConsumerModule;
import com.remoter.basic.bean.support.ProviderModule;
import com.remoter.basic.bean.support.RemoterRequest;
import com.remoter.basic.configure.IConfiguration;
import com.remoter.basic.configure.support.AbstractConfiguration;
import com.remoter.basic.consumer.IConsumer;
import com.remoter.basic.context.IContext;
import com.remoter.basic.monitor.IMonitor;
import com.remoter.basic.provider.IProvider;
import com.remoter.basic.registry.IRegistry;
import com.remoter.basic.transport.IServer;
import com.remoter.basic.util.Final;
import com.remoter.basic.util.NetUtil;
import com.remoter.basic.util.ServiceLoader;
import com.remoter.basic.util.StringUtil;

/**
 * @author			koko
 * @date 			2017-08-09 10:18:21
 * @description 	类功能说明
 */
public abstract class AbstractContext implements IContext{
	
	protected static final Logger logger = LoggerFactory.getLogger(AbstractContext.class);
	
	protected final IConfiguration configuration;
	protected final IProvider provider;
	protected final IConsumer consumer;
	protected final IRegistry registry;
	
	public AbstractContext(){
		configuration = AbstractConfiguration.getConfiguration();
		provider = ServiceLoader.getService(IProvider.class,configuration.getOption(Final.O_VAL_PROVIDER));
		consumer = ServiceLoader.getService(IConsumer.class,configuration.getOption(Final.O_VAL_CONSUMER));
		registry = ServiceLoader.getService(IRegistry.class,configuration.getOption(Final.O_VAL_REGISTRY));
		this.initMonitor();
	}
	
	@Override
	public void close() throws IOException {
		if(null != provider){
			provider.close();
		}
		if(null != consumer){
			consumer.close();
		}
		if(null != registry){
			registry.close();
		}
	}

	@Override
	public ProviderModule getProviderModule(RemoterRequest remoterRequest) {
		return this.provider.getProviderModule(remoterRequest);
	}

	@Override
	public ConsumerModule getConsumerModule(RemoterRequest remoterRequest) {
		return this.consumer.getConsumer(remoterRequest);
	}

	@Override
	public ProviderModule createProviderModule(String protocol){
		ProviderModule module = new ProviderModule();
		module.setServer(this.configuration.getOption(Final.O_VAL_SERVER));
		if(StringUtil.isBlank(protocol)){
			protocol = this.configuration.getOption(Final.O_VAL_PROTOCOL);
		}
		if(StringUtil.isNotBlank(protocol)){
			IServer server = ServiceLoader.getService(IServer.class,protocol);
			InetSocketAddress address = server.getLocalAddress();
			module.setHost(address.getHostString());
			module.setPort(address.getPort());
			module.setProtocol(protocol);
		}
		return module;
	}
	
	@Override
	public IServer attachProvider(ProviderModule providerModule)throws Exception{
		return this.provider.getServer(providerModule, true);
	}

	@Override
	public ConsumerModule createConsumerModule(String protocol){
		ConsumerModule module = new ConsumerModule();
		if(StringUtil.isBlank(protocol)){
			protocol = this.configuration.getOption(Final.O_VAL_PROTOCOL);
		}
		module.setProtocol(protocol);
		module.setServer(this.configuration.getOption(Final.O_VAL_SERVER));
		module.setHost(NetUtil.getLocalAddress().getHostAddress());
		module.setPort(0);
		return module;
	}
	
	@Override
	public <T> T attachConsumer(Class<T> type,ConsumerModule consumerModule) throws Exception {
		this.consumer.attachConsumer(consumerModule);;
		return this.consumer.getConsumerProxy(type, consumerModule);
	}

	@Override
	public void detachProviderModule(ProviderModule providerModule)throws Exception{
		this.provider.unBind(providerModule);
	}

	@Override
	public void detachConsumerModule(ConsumerModule consumerModule)throws Exception{
		this.consumer.detachConsumer(consumerModule);
	}
	
	private void initMonitor(){
		String monitorName = this.configuration.getOption(Final.O_VAL_MONITOR);
		if(StringUtil.isBlank(monitorName)){
			return;
		}
		try{
			IMonitor monitor = ServiceLoader.getService(IMonitor.class,monitorName);
			if(null == monitor){
				logger.warn("monitor not found");
				return;
			}
			ProviderModule module = this.createProviderModule(null);
			module.setType(IMonitor.class.getName());
			module.setBean(IMonitor.ID);
			module.setInstance(monitor);
			this.attachProvider(module);
		}catch(Exception e){
			logger.error(e.getMessage(),e);
		}
	}
	
}